package cn.sxt.sys.service.impl;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.zip.ZipInputStream;
import org.activiti.engine.FormService;
import org.activiti.engine.HistoryService;
import org.activiti.engine.IdentityService;
import org.activiti.engine.ManagementService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.impl.identity.Authentication;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import cn.sxt.sys.constast.SYS_Constast;
import cn.sxt.sys.domain.LeaveBill;
import cn.sxt.sys.mapper.LeaveBillMapper;
import cn.sxt.sys.service.WorkFlowService;
import cn.sxt.sys.utils.DataGridView;
import cn.sxt.sys.utils.SessionUtils;
import cn.sxt.sys.vo.WorkFlowVo;
import cn.sxt.sys.vo.act.ActCommentEntity;
import cn.sxt.sys.vo.act.ActDeploymentEntity;
import cn.sxt.sys.vo.act.ActHistoricTaskInstanceEntity;
import cn.sxt.sys.vo.act.ActProcessDefinitionEntity;
import cn.sxt.sys.vo.act.ActTaskEntity;

@Service
public class WorkFlowServiceImpl implements WorkFlowService {

	@Autowired
	private RepositoryService repositoryService;
	@Autowired
	private RuntimeService runtimeService;
	@Autowired
	private TaskService taskService;
	@Autowired
	private HistoryService historyService;
	@Autowired
	private IdentityService identityService;
	@Autowired
	private ManagementService managementService;
	@Autowired
	private FormService formService;

	@Autowired
	private LeaveBillMapper leaveBillMapper;

	@Override
	public DataGridView loadAllProcessDeployment(WorkFlowVo workFlowVo) {
		String deploymentName = workFlowVo.getDeploymentName();
		if (null == deploymentName) {
			deploymentName = "";
		}
		// 查 总条数
		long count = repositoryService.createDeploymentQuery().deploymentNameLike("%" + deploymentName + "%").count();
		// 分页查询
		List<Deployment> list = repositoryService.createDeploymentQuery().deploymentNameLike("%" + deploymentName + "%")
				.listPage((workFlowVo.getPage() - 1) * workFlowVo.getLimit(), workFlowVo.getLimit());

		List<ActDeploymentEntity> entities = new ArrayList<>();
		for (Deployment d : list) {
			ActDeploymentEntity entity = new ActDeploymentEntity();
			BeanUtils.copyProperties(d, entity);
			entities.add(entity);
		}
		return new DataGridView(count, entities);
	}

	@Override
	public DataGridView loadAllProcessDef(WorkFlowVo workFlowVo) {
		String deploymentName = workFlowVo.getDeploymentName();
		if (null == deploymentName) {
			deploymentName = "";
		}
		// 先查出 部署id
		List<Deployment> list = repositoryService.createDeploymentQuery().deploymentNameLike("%" + deploymentName + "%")
				.list();
		if (list.size() == 0) {
			return new DataGridView(0L, list);
		} else {
			Set<String> deploymentIds = new HashSet<>();
			for (Deployment d : list) {
				deploymentIds.add(d.getId());
			}
			// 总条数
			long count = repositoryService.createProcessDefinitionQuery().deploymentIds(deploymentIds).count();
			// 分页
			List<ProcessDefinition> data = repositoryService.createProcessDefinitionQuery().deploymentIds(deploymentIds)
					.listPage((workFlowVo.getPage() - 1) * workFlowVo.getLimit(), workFlowVo.getLimit());
			List<ActProcessDefinitionEntity> entities = new ArrayList<>();
			for (ProcessDefinition p : data) {
				ActProcessDefinitionEntity entity = new ActProcessDefinitionEntity();
				BeanUtils.copyProperties(p, entity);
				entities.add(entity);
			}
			return new DataGridView(count, entities);
		}
	}

	@Override
	public void addDeployment(InputStream inputStream, String deploymentName) {
		ZipInputStream zipInputStream = new ZipInputStream(inputStream);
		repositoryService.createDeployment().name(deploymentName).addZipInputStream(zipInputStream).deploy();
	}

	@Override
	public int deleteDeployment(String deploymentId) {
		repositoryService.deleteDeployment(deploymentId);
		return 1;
	}

	@Override
	public InputStream viewProcessImage(String deploymentId) {
		// 根据部署id查流程对象
		ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
				.deploymentId(deploymentId).singleResult();
		// 从流程定义对象 里取出图片名
		String diagramResourceName = processDefinition.getDiagramResourceName();
		InputStream inputStream = repositoryService.getResourceAsStream(deploymentId, diagramResourceName);
		return inputStream;
	}

	@Override
	public void startLeaveBillProcess(Integer id) {
		// 得到流程 key
		String processDefinitionKey = LeaveBill.class.getSimpleName();
		// 设置流程变量，设置办理人
		Map<String, Object> variables = new HashMap<>();
		// 得到当前用户 的名
		String name = SessionUtils.getUserNameInSession("user");
		variables.put("username", name);
		// 业务key
		String businessKey = processDefinitionKey + "_" + id;
		runtimeService.startProcessInstanceByKey(processDefinitionKey, businessKey, variables);

		// 在将请假状态由未提交-->审批中，0-->1
		LeaveBill record = new LeaveBill();
		record.setId(id);
		record.setState(String.valueOf(SYS_Constast.TYPE_PUBLIC_ONE));
		leaveBillMapper.updateByPrimaryKeySelective(record);
	}

	@Override
	public DataGridView queryCurrentUserTask(WorkFlowVo workFlowVo) {
		// 当前用户的登录名
		String name = SessionUtils.getUserNameInSession("user");
		// 2,得到当前用户待办任务的总数
		long count = taskService.createTaskQuery().taskAssignee(name).count();
		// 3,查询任务列表
		List<Task> list = taskService.createTaskQuery().taskAssignee(name).orderByTaskCreateTime().desc()
				.listPage((workFlowVo.getPage() - 1) * workFlowVo.getLimit(), workFlowVo.getLimit());

		// 转换集合
		List<ActTaskEntity> entities = new ArrayList<>();
		for (Task task : list) {
			ActTaskEntity entity = new ActTaskEntity();
			BeanUtils.copyProperties(task, entity);
			entities.add(entity);
		}
		System.out.println();
		return new DataGridView(count, entities);
	}

	/**
	 * 根据任务id查请假单信息
	 */
	@Override
	public LeaveBill queryLeaveBillByTaskId(String taskId) {
		// 1,根据任务id查任务对象
		Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
		// 2,根据任务对象查到 实例id
		String processInstanceId = task.getProcessInstanceId();
		// 3，根据实例id 查到 流程实例
		ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
				.processInstanceId(processInstanceId).singleResult();
		// 4，从流程实例 取出业务key :bussinessKey
		String businessKey = processInstance.getBusinessKey();
		// 5,从业务key 中截取请假单的id
		String id = businessKey.split("_")[1];
		// 6，根据请假单id 查请假单
		LeaveBill leaveBill = leaveBillMapper.selectByPrimaryKey(Integer.valueOf(id));
		return leaveBill;
	}

	/**
	 * 根据任务id查按钮的集合
	 */
	@Override
	public List<String> queryOutcomeByTaskId(String taskId) {
		List<String> outcomes = new ArrayList<>();
		// 1,根据任务id查任务
		Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
		// 2,得到流程定义id
		String processDefinitionId = task.getProcessDefinitionId();
		// 3，取到当前活动id usertask1
		String activityId = task.getTaskDefinitionKey();
		// 4，用流程定义id查 流程定义对象 里的XML数据
		ProcessDefinitionEntity processDefinitionEntity = (ProcessDefinitionEntity) repositoryService
				.getProcessDefinition(processDefinitionId);
		// 5,用活动id从流程定义里查出节点
		ActivityImpl activityImpl = processDefinitionEntity.findActivity(activityId);
		// 6,取出当前活动节点的 连线信息
		List<PvmTransition> outgoingTransitions = activityImpl.getOutgoingTransitions();
		if (null != outgoingTransitions && outgoingTransitions.size() > 0) {
			for (PvmTransition pvmTransition : outgoingTransitions) {
				Object name = pvmTransition.getProperty("name");
				outcomes.add(name.toString());
			}
		}
		return outcomes;
	}

	/**
	 * 根据任务id查 批注信息
	 */
	@Override
	public DataGridView queryCommonsByTaskId(String taskId) {
		// taskService.getTaskComments查询出的是当前任务的批注
		// List<Comment> comments = taskService.getTaskComments(taskId);

		// 1，根据任务id查任务对象
		Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
		// 2,从任务对象 里得到流程实例id
		String processInstanceId = task.getProcessInstanceId();
		// 3,查整个流程实例里面所有的批注信息
		List<Comment> comments = taskService.getProcessInstanceComments(processInstanceId);
		List<ActCommentEntity> entities = new ArrayList<>();
		for (Comment comment : comments) {
			ActCommentEntity entity = new ActCommentEntity();
			BeanUtils.copyProperties(comment, entity);
			entities.add(entity);
		}
		return new DataGridView(Long.valueOf(entities.size()), entities);
	}

	/**
	 * 根据任务id完成任务 并添加批注信息
	 */
	@Override
	public void completeTask(WorkFlowVo workFlowVo) {
		String taskId = workFlowVo.getTaskId(); // 任务id
		String outcome = workFlowVo.getOutcome(); // 连线名
		String comment = workFlowVo.getComment();// 批注信息
		Integer id = workFlowVo.getId(); // 请假单id
		// 1，创建流程变量map
		Map<String, Object> variables = new HashMap<>();
		variables.put("outcome", outcome);
		// 2，根据任务id查任务对象
		Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
		// 3,得到流程实例id
		String processInstanceId = task.getProcessInstanceId();
		// 4，得到当前用户
		String username = SessionUtils.getUserNameInSession("user");
		// 5,设置当前线程用户的局部变量
		Authentication.setAuthenticatedUserId(username);
		// 6,添加批注信息
		/**
		 * 因为批注 是属性某个办理人 所以一空设置办理人的ID。可以查看addComment-->AddcomentAdd--> String userId =
		 * Authentication.getAuthenticatedUserId(); CommentEntity comment = new
		 * CommentEntity(); comment.setUserId(userId);
		 */
		taskService.addComment(taskId, processInstanceId, "[" + outcome + "]" + comment);
		// 7，完成任务
		taskService.complete(taskId, variables);
		// 8，判断任务是否完成
		ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
				.processInstanceId(processInstanceId).singleResult();
		if (null == processInstance) {
			// 任务完成，修改请假单的状态
			LeaveBill record = new LeaveBill();
			record.setId(id);
			if (outcome.equals("放弃")) {
				record.setState(String.valueOf(SYS_Constast.TYPE_LEAVEBILL_STATE_THREE));
			} else {
				record.setState(String.valueOf(SYS_Constast.TYPE_LEAVEBILL_STATE_TOW));
			}
			leaveBillMapper.updateByPrimaryKeySelective(record);
		}
	}

	/**
	 * 根据任务id查流程定义对象
	 */
	@Override
	public ProcessDefinition queryProcessDefinitionByTaskId(String taskId) {
		// 1，根据任务id查任务
		Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
		// 2，从任务里取出流程定义id
		String processDefinitionId = task.getProcessDefinitionId();
		// 3,根据流程定义id查流程定义对象
		return repositoryService.createProcessDefinitionQuery().processDefinitionId(processDefinitionId).singleResult();
	}

	/**
	 * 根据任务id查当前办理任务的坐标
	 */
	@Override
	public Map<String, Object> queryCoordinateByTaskId(String taskId) {
		Map<String, Object> map = new HashMap<>();
		// 1，根据任务id查任务
		Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
		// 2，得到流程定义id
		String processDefinitionId = task.getProcessDefinitionId();
		// 3，取到当前活动的id usertask1
		String activityId = task.getTaskDefinitionKey();
		// 4,用流程定义id查流程定义对象里的XML数据
		ProcessDefinitionEntity processDefinitionEntity = (ProcessDefinitionEntity) repositoryService
				.getProcessDefinition(processDefinitionId);
		// 5，用活动id从流程定义里查出节点
		ActivityImpl activityImpl = processDefinitionEntity.findActivity(activityId);

		map.put("x", activityImpl.getX());
		map.put("y", activityImpl.getY());
		map.put("width", activityImpl.getWidth());
		map.put("height", activityImpl.getHeight());
		return map;
	}

	/**
	 * 根据请假单id查批注
	 */
	@Override
	public DataGridView queryCommonsByLeaveBillId(Integer id) {
		//因为用户要请假单页面查询审批进度时,这个任务已经审批完成
		//act_ru表里面就没有数据数据，但是act_hi里面有
		// 1，组装bussinessKey
		String businessKey = LeaveBill.class.getSimpleName()+"_"+id;
		// 2,根据businessKey去历史流程实例里查询历史流程实例对象
		HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
		.processInstanceBusinessKey(businessKey).singleResult();
		//3，从历史流程实例对象取出流程实例id
		String processInstanceId = historicProcessInstance.getId();
		// 4,查整个流程实例里面所有的批注信息
		List<Comment> comments = taskService.getProcessInstanceComments(processInstanceId);
		List<ActCommentEntity> entities = new ArrayList<>();
		for (Comment comment : comments) {
			ActCommentEntity entity = new ActCommentEntity();
			BeanUtils.copyProperties(comment, entity);
			entities.add(entity);
		}
		return new DataGridView(Long.valueOf(entities.size()), entities);
	}

	/**
	 * 根据当前用户名称查询历史审批记录
	 */
	@Override
	public DataGridView queryHistoryTaskByAssignee(WorkFlowVo workFlowVo) {
		long count = this.historyService.createHistoricTaskInstanceQuery().taskAssignee(workFlowVo.getAssignee()).count();
		List<HistoricTaskInstance> list = this.historyService.createHistoricTaskInstanceQuery().taskAssignee(workFlowVo.getAssignee())
		.listPage((workFlowVo.getPage() - 1) * workFlowVo.getLimit(), workFlowVo.getLimit());
		List<ActHistoricTaskInstanceEntity> entities=new ArrayList<>();
		for (HistoricTaskInstance h : list) {
			ActHistoricTaskInstanceEntity entity=new ActHistoricTaskInstanceEntity();
			BeanUtils.copyProperties(h, entity);
			entities.add(entity);
		}
		return new DataGridView(count, entities);
	}

}
